package pub.wkq.company.controller;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import pub.wkq.api.controller.intercept.JWTCurrentUserInterceptor;
import pub.wkq.common.base.BaseInfoProperties;
import pub.wkq.common.result.JSONResult;
import pub.wkq.common.result.ResponseStatusEnum;
import pub.wkq.common.utils.JWTUtils;
import pub.wkq.common.utils.SerializationUtils;
import pub.wkq.pojo.Users;
import pub.wkq.vo.SaasUserVO;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
 * <h1>公司通行证控制器</h1>
 */
@Slf4j
@RestController
@RequestMapping("/saas/passport")
public class SaasPassportController extends BaseInfoProperties {
    @Resource
    private JWTUtils jwtUtils;


    /**
     * <h2>获取扫码登录的 token</h2>
     */
    @RequestMapping("/getQRToken")
    public JSONResult getQRToken() {
        //生成扫码登录的 token
        String qrToken = UUID.randomUUID().toString().replace("-", "");
        //把 qrToken 存入 redis ，有效期 5 分钟。默认二维码超时，则需要重新生成二维码
        redis.set(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken, qrToken, 60 * 5);
        //存入 redis 标记当前的 qrToken 未被扫码读取
        redis.set(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken, "0", 60 * 5);
        //返回二维码 token, 用于生成二维码，让前端下一次请求的时候要带上 qrToken
        return JSONResult.ok(qrToken);
    }

    /**
     * <h2>手机端使用HR角色进行扫码操作</h2>
     */
    @PostMapping("scanCode")
    public JSONResult scanCode(String qrToken, HttpServletRequest request) {
        //判空  - qrToken
        if (StringUtils.isBlank(qrToken)) {
            return JSONResult.error();
        }
        String redisQrToken = redis.get(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken);
        if (!Objects.equals(qrToken, redisQrToken)) {
            return JSONResult.error();
        }
        String appUserId = request.getHeader("appUserId");
        String appUserToken = request.getHeader("appUserToken");
        if (StringUtils.isBlank(appUserId) || StringUtils.isBlank(appUserToken)) {
            return JSONResult.error();
        }
        //校验用户 token
        String userJson = jwtUtils.checkJwt(appUserToken.split("@")[1]);
        if (StringUtils.isBlank(userJson)) {
            return JSONResult.errorCustom(ResponseStatusEnum.HR_TICKET_INVALID);
        }
        //执行后续正常业务
        //生成预登录 token
        String preToken = UUID.randomUUID().toString().replace("-", "");
        //这个操作的目的是为了将原来的 qrToken 做一个覆盖
        redis.set(SAAS_PLATFORM_LOGIN_TOKEN + ":" + qrToken, preToken, 60 * 5);
        //redis  写入标记，当前 qrToken 需要被读取并且失效覆盖。
        redis.set(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken, "1," + preToken, 60 * 5);
        //返回给手机端， app 下次请求携带 preToken
        return JSONResult.ok(preToken);
    }

    /**
     * 3. SAAS 网页端在每隔一段时间（3秒）定时查询 qrToken 是否被读取，用于页面的展示标记判断
     * 前端处理：限制用户在页面不操作而频繁发起调用。
     * 当前二维码是否已被扫码
     * 如果说使用 webscocket 或者 netty ，可以在 app 扫码之后，在上一个接口，直接通信浏览器端，进行页面的刷新
     */
    @PostMapping("codeHasBeenRead")
    public JSONResult codeHasBeenRead(String qrToken) {
        List list = new ArrayList();
        String readStr = redis.get(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken);
        if (StringUtils.isBlank(readStr)) {
            return JSONResult.ok(list);
        }
        String[] readArray = readStr.split(",");
        if (readArray.length >= 2) {
            list.add(readArray[0]);
            list.add(readArray[1]);
        } else {
            list.add(readArray[0]);
        }
        return JSONResult.ok(list);
    }

    /**
     * 4. 手机端点击确认登录，携带 preToken 和 qrToken 与后端进行判断，如果校验通过，则登录成功。
     * 如果使用 websocket 或者 netty ，可以在此直接通信 H5 进行页面的刷新
     */
    @PostMapping("goQRLogin")
    public JSONResult goQRLogin(String appToken, String qrToken, String preToken) {
        String preTokenRedis = redis.get(SAAS_PLATFORM_LOGIN_TOKEN_READ + ":" + qrToken);
        if (StringUtils.isBlank(preTokenRedis)) {
            return JSONResult.error();
        }
        String[] preTokenArray = preTokenRedis.split(",");
        if (preTokenArray.length != 2) {
            return JSONResult.error();
        }
        if (!Objects.equals(preToken, preTokenArray[1])) {
            return JSONResult.error();
        }

        //校验通过
        String userToken = appToken.split("@")[1];
        String userJson = jwtUtils.checkJwt(userToken);
        log.info("userJson:{}", userJson);
        //存入用户信息到 redis 中,如果使用 webscoket 或者 netty ，可以在此直接通信 H5 进行页面的刷新。
        redis.set(REDIS_SAAS_USER_INFO + ":temp:" + preToken, userJson, 60 * 5);
        return JSONResult.ok();
    }

    /**
     * 5. SAAS 网页端在每隔一段时间（3秒）定时查询 preToken 是否被读取，用于页面的展示标记判断
     */
    @PostMapping("checkLogin")
    public JSONResult checkLogin(String preToken) {
        if (StringUtils.isBlank(preToken)) {
            return JSONResult.error();
        }
        //获得用户临时信息
        String userJson = redis.get(REDIS_SAAS_USER_INFO + ":temp:" + preToken);
        if (StringUtils.isBlank(userJson)) {
            return JSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
        }
        String saasUserToken = jwtUtils.createJwtWithPrefix(userJson, TOKEN_SAAS_PREFIX);
        //存入用户信息，长期有效
        redis.set(REDIS_SAAS_USER_INFO + ":" + saasUserToken, userJson);
        return JSONResult.ok(saasUserToken);
    }
    @GetMapping("info")
    public JSONResult info(String token) {
        if (StringUtils.isBlank(token)) {
            return JSONResult.error();
        }
        String userJson = redis.get(REDIS_SAAS_USER_INFO + ":" + token);
        if (StringUtils.isBlank(userJson)) {
            return JSONResult.errorCustom(ResponseStatusEnum.USER_NOT_EXIST_ERROR);
        }
        Users users = SerializationUtils.deserializeObject(userJson, Users.class);
        SaasUserVO saasUserVO = new SaasUserVO();
        assert users != null;
        BeanUtils.copyProperties(users, saasUserVO);
        return JSONResult.ok(users);
    }
    @PostMapping("logout")
    public JSONResult logout() {
        return JSONResult.ok();
    }
}
